package com.xingchi.tornado.dict.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xingchi.tornado.basic.ErrorCode;
import com.xingchi.tornado.core.context.SpringContextHolder;
import com.xingchi.tornado.core.enums.OperateTypeEnum;
import com.xingchi.tornado.dict.event.DictDataChangeEvent;
import com.xingchi.tornado.dict.mapper.DictItemMapper;
import com.xingchi.tornado.dict.model.domain.DictItemDO;
import com.xingchi.tornado.dict.model.dto.DictGroupQueryDTO;
import com.xingchi.tornado.dict.model.dto.DictItemAddDTO;
import com.xingchi.tornado.dict.model.dto.DictItemDTO;
import com.xingchi.tornado.dict.model.dto.DictItemEditDTO;
import com.xingchi.tornado.dict.model.dto.DictItemQueryDTO;
import com.xingchi.tornado.dict.service.DictGroupService;
import com.xingchi.tornado.dict.service.DictItemService;
import com.xingchi.tornado.exception.BizException;
import com.xingchi.tornado.mybatisplus.service.AbstractBasePlusService;
import com.xingchi.tornado.utils.BeanUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xingchi
 * @date 2025-05-27 15:24
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DictItemServiceImpl extends AbstractBasePlusService<DictItemMapper, DictItemDTO, DictItemQueryDTO, DictItemDO> implements DictItemService {

    @Resource
    private DictGroupService dictGroupService;

    @Override
    public Wrapper<DictItemDO> getWrapper(DictItemQueryDTO query) {
        return Wrappers.<DictItemDO>lambdaQuery()
                .eq(Objects.nonNull(query.getCode()), DictItemDO::getCode, query.getCode())
                .eq(StringUtils.isNotBlank(query.getGroupCode()), DictItemDO::getGroupCode, query.getGroupCode())
                .orderByAsc(BooleanUtils.isTrue(query.getOrderBySort()), DictItemDO::getSort);
    }

    @Override
    public Boolean deleteByGroupCode(String groupCode) {
        BizException.throwIf(StringUtils.isBlank(groupCode), ErrorCode.PARAM_IS_INVALID, "分组code不能为空");

        return this.remove(Wrappers.<DictItemDO>lambdaQuery().eq(DictItemDO::getGroupCode, groupCode));
    }

    @Override
    public Boolean deleteByGroupCode(List<String> groupCodes) {
        BizException.throwIf(CollectionUtils.isEmpty(groupCodes), ErrorCode.PARAM_IS_INVALID, "分组集合code不能为空");
        return this.remove(Wrappers.<DictItemDO>lambdaQuery().in(DictItemDO::getGroupCode, groupCodes));
    }

    /**
     * 修改分组项的分组code
     *
     * @param oldCode 旧分组code
     * @param newCode 新分组code
     * @return 是否修改成功
     */
    @Override
    public Boolean updateGroupCode(String oldCode, String newCode) {
        BizException.throwIf(StringUtils.isBlank(oldCode), ErrorCode.PARAM_IS_INVALID, "旧分组code不能为空");
        BizException.throwIf(StringUtils.isBlank(newCode), ErrorCode.PARAM_IS_INVALID, "新分组code不能为空");

        return this.update(Wrappers.<DictItemDO>lambdaUpdate().set(DictItemDO::getGroupCode, newCode).eq(DictItemDO::getGroupCode, oldCode));
    }

    /**
     * 添加字典项
     *
     * @param dictItem 字典项
     * @return 字典项id
     */
    @Override
    public Long addItem(DictItemAddDTO dictItem) {

        DictItemDTO item = checkAndConvertDictItemDTO(dictItem);
        this.insert(item);
        SpringContextHolder.publishEvent(new DictDataChangeEvent(item.getGroupCode(), OperateTypeEnum.INSERT));
        return item.getId();
    }

    private DictItemDTO checkAndConvertDictItemDTO(DictItemAddDTO dictItem) {
        String groupCode = dictItem.getGroupCode();
        boolean exists = dictGroupService.exists(DictGroupQueryDTO.builder().code(groupCode).build());
        BizException.throwIf(!exists, ErrorCode.PARAM_IS_INVALID, "分组不存在");

        Integer code = dictItem.getCode();
        DictItemDTO dictItemDTO = this.selectOne(DictItemQueryDTO.builder().code(code).groupCode(groupCode).build());
        BizException.throwIf(dictItemDTO != null, ErrorCode.PARAM_IS_INVALID, "字典项code不能重复");

        // dictItemDTO = this.selectOne(DictItemQueryDTO.builder().name(dictItem.getName()).groupCode(groupCode).build());
        // BizException.throwIf(dictItem.getName().equals(dictItemDTO.getName()), ErrorCode.PARAM_IS_INVALID, "字典项名称不能重复");

        // 执行添加
        return BeanUtils.convert(dictItem, DictItemDTO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addItemBatch(List<DictItemAddDTO> dictItem) {
        if (CollectionUtils.isEmpty(dictItem)) {
            return;
        }

        List<DictItemDTO> list = dictItem.stream().map(this::checkAndConvertDictItemDTO).collect(Collectors.toList());
        this.saveBatch(list);

        Map<String, List<DictItemDTO>> groupMappings = list.stream().collect(Collectors.groupingBy(DictItemDTO::getGroupCode));
        for (Map.Entry<String, List<DictItemDTO>> entry : groupMappings.entrySet()) {
            SpringContextHolder.publishEvent(new DictDataChangeEvent(entry.getKey(), OperateTypeEnum.INSERT));
        }
    }

    /**
     * 更新字典项
     *
     * @param dictItem 字典项
     * @return 是否更新成功
     */
    @Override
    public Boolean updateItem(DictItemEditDTO dictItem) {

        DictItemDTO dbDictItem = this.selectById(dictItem.getId());
        BizException.throwIf(dbDictItem == null, ErrorCode.DATA_NOT_FOUND, "字典项不存在");

        // 判断code和name是否重复
        boolean exists = this.exists(Wrappers.lambdaQuery(DictItemDO.class)
                .eq(DictItemDO::getGroupCode, dbDictItem.getGroupCode())
                .nested(wrapper -> wrapper
                        .eq(DictItemDO::getCode, dictItem.getCode())
                        .or()
                        .eq(DictItemDO::getName, dictItem.getName())));

        BizException.throwIf(exists, ErrorCode.PARAM_IS_INVALID, "字典项code或name不能重复");

        DictItemDTO item = BeanUtils.convert(dictItem, DictItemDTO.class);
        this.updateById(item);
        SpringContextHolder.publishEvent(new DictDataChangeEvent(item.getGroupCode(), OperateTypeEnum.UPDATE));
        return true;
    }

    @Override
    public Boolean deleteItem(Long id) {

        DictItemDTO dictItemDTO = this.selectById(id);
        BizException.throwIf(dictItemDTO == null, ErrorCode.DATA_NOT_FOUND, "字典项不存在");

        Boolean status = this.deleteById(id);
        if (status) {
            SpringContextHolder.publishEvent(new DictDataChangeEvent(dictItemDTO.getGroupCode(), OperateTypeEnum.DELETE));
        }
        return status;
    }
}
